#ifndef _HJ212_CLIENT_DEF_H
#define _HJ212_CLIENT_DEF_H

#include <time.h>
#include <string.h>

#include "hj212_client_config.h"

#include "rtservice.h"
#include "gen_blkqueue.h"

#define HJ212_CLIENT_VERSIONS "v1.0.0"

struct hj212_client;
struct hj212_datastream;

enum hj212_datamsg_type
{
    HJ212_MSG_TYPE_RTD = 0, // 实时数据
    HJ212_MSG_TYPE_MIN,     // 分钟数据
    HJ212_MSG_TYPE_HOUR,    // 小时数据
    HJ212_MSG_TYPE_DAY,     // 日数据
    HJ212_MSG_TYPE_POLSTETE,// 污染物状态 
    HJ212_MSG_TYPE_NUM,
};
enum hj212_datastream_state
{
    HJ212_DATASTREAM_EMPTY = 0, // 数据流无数据
    HJ212_DATASTREAM_IDLE,      // 有数据并空闲，可以发送数据
    HJ212_DATASTREAM_BUSY,      // 数据流忙，一般为对方未响应
};
enum hj212_response_state
{
    HJ212_RESPONSE_IDLE = 0, // 空闲
    HJ212_RESPONSE_WAITINT,  // 正在等待
    // HJ212_RESPONSE_MATCH_SUCCESSFUL,    // 匹配成功
};
enum hj212_command
{
    GET_HJ212_SYS_CODE,        // 系统编码
    GET_HJ212_ACCESS_PWD,      // 访问密码
    GET_HJ212_CLIENT_MN,       // 客户端的MN
    GET_HJ212_PROTOCOL,        // 协议类型
    GET_HJ212_RTD_CYCLE,       // 实时周期 (秒)
    GET_HJ212_MIN_CYCLE,       // 分钟周期 (秒)
    GET_HJ212_HEARTBEAT_CYCLE, // 心跳周期 (秒)
    GET_HJ212_MAXRET,          // 重发次数
    GET_HJ212_SEND_INTER,      // 发送间隔 (毫秒)
    GET_HJ212_STREAM_TIMEOUT,  // 超时时间 (秒) (数据流等待回应的超时)

    SET_HJ212_SYS_CODE,        // 系统编码
    SET_HJ212_ACCESS_PWD,      // 访问密码
    SET_HJ212_CLIENT_MN,       // 客户端的MN
    SET_HJ212_PROTOCOL,        // 协议类型
    SET_HJ212_RTD_CYCLE,       // 实时周期 (秒)
    SET_HJ212_MIN_CYCLE,       // 分钟周期 (秒)
    SET_HJ212_HEARTBEAT_CYCLE, // 心跳周期 (秒)
    SET_HJ212_MAXRET,          // 重发次数
    SET_HJ212_SEND_INTER,      // 发送间隔 (毫秒)
    SET_HJ212_STREAM_TIMEOUT,  // 超时时间 (秒) (数据流等待回应的超时
};
enum hj212_protocol_type
{
    HJ212_PROTOCOL_2017 = 0,
    HJ212_PROTOCOL_2005,
};

enum hj212_event_type
{
    HJ_EVENT_NONE = 0,                  // 空
    HJ_EVENT_STREAM_TRANSFER,           // 流传输事件
    HJ_EVENT_STREAM_TRANSFER_TIMEOUT,   // 流传输超时事件
    HJ_EVENT_REQUEST,                   // 请求事件
    HJ_EVENT_INVALID_REQUEST,           // 无效请求
    HJ_EVENT_REQUEST_FAILED,            // 请求执行失败
    HJ_EVENT_REQUEST_SUCCESS,           // 请求执行成功
};

struct hj212_event
{
    int type;           // 事件类型
    time_t timestamp;   // 事件产生时的时间戳
};

struct hj212_stream_transfer_event // 流传输事件
{
    struct hj212_event parent;
    int cn;
    time_t datatime;
};

struct hj212_request_event  // 请求事件
{
    struct hj212_event parent;
    int cn;
    int error_code;  // 响应编码
};

/* 发送缓冲 */
struct send_buffer
{
    char mempool[HJ212_PACK_MAX_SIZE];
    rt_list_t list;

    void *parameters;
    void (*send_callback)(struct hj212_client *, void *);    // 发送完成时调用
};

/* msg基类 */
struct hj212_msg
{
    char qn[HJ212_QN_MAX_LEN];
    char st[HJ212_SYSCODE_MAX_LEN];
    int cn;
    char access_pwd[HJ212_ACCESS_PWD_MAX_LEN];
    char mn[HJ212_MN_MAX_LEN];
    int flag;
};
/* 通用的msg (主要用于除了数据之外的其他报文) */
struct hj212_generalmsg
{
    struct hj212_msg parent;
    char cp[HJ212_GENERAL_CP_MAX_LEN];
};
/* 带数据的msg (用于数据报文，只有数据报文才需要分包) */
struct hj212_datamsg
{
    struct hj212_msg parent;
    int pnum;
    int pno;
    time_t datatime;

    int type; // 数据类型 - 不同数据类型打包方式不一样
    struct gen_blk_queue queue;
};

/* 响应控制块 */
struct hj212_response;
typedef int (*hj212_response_match_t)(struct hj212_response *res, struct hj212_generalmsg *msg, uint32_t package_state, void *param);
typedef int (*hj212_response_timeout_t)(struct hj212_response *res, void *param);
struct hj212_response
{
    int cn;                            // 要求响应报文必须匹配的CN字段
    char qn[HJ212_QN_MAX_LEN];         // 要求响应报文必须匹配的QN字段
    char cp[HJ212_GENERAL_CP_MAX_LEN]; // 要求响应报文必须匹配的CP字段

    hj212_response_match_t match;
    void *match_param;

    hj212_response_timeout_t timeout_handle;
    void *timeout_param;
    time_t register_time;
    int timeout;

    int state; // 状态

    rt_list_t list;
};
/* 请求控制块 */
struct hj212_request;
typedef int (*request_handle_t)(struct hj212_client *client, struct hj212_request *request);
struct hj212_request
{
    char qn[HJ212_QN_MAX_LEN]; // 要求响应报文必须匹配的QN字段
    /* 处理机 */
    request_handle_t handle;

    rt_list_t list;
    
    int cn;
};

/* *
 * 尝试匹配一个请求,
 * 匹配成功时应该在这个函数中
 * 【创建请求控制块并插入到客户端请求列表】
 * 或者
 * 【进行必要的错误返回】
 */
typedef int (*hj212_request_match)(struct hj212_client *client,
                                   struct hj212_generalmsg *msg,
                                   uint32_t package_state);

/* 数据流相关 */
struct hj212_datasource
{
    /* 引用一个msg, 从数据源中引用一个datamsg, 类比malloc */
    struct hj212_datamsg *(*references)(struct hj212_datasource *source);
    /* 解除一个msg引用, 回收, 类比free */
    void (*dereference)(struct hj212_datasource *source, struct hj212_datamsg *msg);
    /* 检查数据源中是否还有数据 */
    int (*is_empty)(struct hj212_datasource *source);
    /* 从数据源中取出一条数据, 传入的msg应该由references获得 */
    int (*next)(struct hj212_datasource *source, struct hj212_datamsg *msg);
};

/* 数据流 */
struct hj212_datastream
{
    struct hj212_datamsg *msg;          // 数据暂存
    struct hj212_response response;     // 响应
    struct hj212_datasource *source;    // 数据源

    struct hj212_client *owner;         // 持有者

    struct hj212_stream_transfer_event transfer_event;  // 传输时间
    int event_valid;    // 事件有效

    int type; // 数据流类型

    int maxret;  // 最大重发次数
    int count;   // 当前发送次数
    int itemnum; // 数据项数量
};

/* HJ212 客户端 */
struct hj212_client;
struct hj212_client_ops
{
    /* 系统相关 */
    int (*command)(struct hj212_client *client, int cmd, void *args); // 命令接口，暂时用于获取/设置系统参数
    time_t (*current_timestamp)(void);                                // 获取当前时间
    int (*set_current_timestamp)(time_t time);                        // 获取当前时间
    struct timeval(*current_subsec)(void);                            // 获取当前精确时间戳

    /* OS特性 */
    void (*lock)(struct hj212_client *client);
    int (*trylock)(struct hj212_client *client);
    void (*unlock)(struct hj212_client *client);

    /* 内存分配相关 */
    void *(*malloc)(size_t size);
    void *(*calloc)(unsigned int num, size_t size);
    void (*free)(void *ptr);
    /* 设备IO */
    int (*dev_open)(struct hj212_client *client, int flag); // 设备操作接口
    int (*dev_close)(struct hj212_client *client);
    int (*dev_state)(struct hj212_client *client);
    int (*dev_recv)(struct hj212_client *client, uint8_t *buffer, int len, int timeout);
    int (*dev_send)(struct hj212_client *client, const uint8_t *buffer, int len);

    /* 数据相关接口 */
    struct hj212_datasource *(*get_data_source)(struct hj212_client *client, int type);                                 // 获取主动上报的数据源
    struct hj212_datasource *(*create_hisdata_source)(struct hj212_client *client, int type, time_t begin, time_t end); // 创建历史数据的数据源(用于补足数据和上位机提取数据)
    void (*delete_data_source)(struct hj212_client *client, struct hj212_datasource *source);

    /* 事件相关接口 */
    void (*event_push)(struct hj212_client *client, struct hj212_event *event);
};
struct hj212_client
{
    int id;
#if 0
    int login; // 登陆状态
#endif
    struct send_buffer *sendbuf;
    rt_list_t idle_sendbuf_list;   // 空闲发送缓冲块
    rt_list_t sendbuf_list;        // 待发送的缓冲块待
    struct timeval last_send_time; // 上一次发送的时间

    uint8_t recv_buffer[HJ212_RECV_BUFFER_SIZE]; // 接收字节流缓冲
    struct hj212_generalmsg recv_msg;            // 接收的消息缓冲

    struct hj212_datastream *stream[HJ212_MSG_TYPE_NUM]; // 主动上发的数据流(对应每种类型一种)
    uint32_t push_enable;

    struct hj212_datastream *trigger_stream[HJ212_MSG_TYPE_NUM]; // 外部触发的数据流

    time_t last_heartbeat_time; // 最近一条心跳数据的时间

    rt_list_t request_list;  // 请求队列，所有待处理的请求都应该在这里
    rt_list_t response_list; // 响应队列，所有待响应事件都应该在这里

    /* HJ212客户端的外部操作 */
    const struct hj212_client_ops *ops; // 需要实现的接口
    /* 以下所有变量皆为临时变量，函数内有效，不跨函数使用，定义在这里只是为了不频繁申请内存 */
    // uint8_t tmp_buffer[1024];
};
typedef struct hj212_client *hj212_client_t;

#endif
